home *** CD-ROM | disk | FTP | other *** search
/ hornet.scene.org / hornet.scene.org FTP 11-25-2012.zip / hornet.scene.org FTP 11-25-2012 / code / 3d / trifill / texmap / fatmap.txt < prev    next >
Text File  |  2012-06-16  |  72KB  |  1,823 lines

  1.  
  2.             Fast affine texture mapping (fatmap.txt)
  3.             ----------------------------------------
  4.  
  5.                               by
  6.                                   
  7.                         Mats Byggmastar
  8.                              a.k.a.
  9.                          MRI / Doomsday
  10.                         mri@penti.sit.fi
  11.  
  12.                  8 Jul. 1996  Jakobstad, Finland
  13.                    19 Jun. 1996  Espoo, Finland
  14.  
  15.            Read this today, it might be obsolete tomorrow.
  16.  
  17.   Feel free to upload this document to wherever you find appropriate,
  18.       as long as you keep it in it's original, unmodified form.
  19.     This is free information, you may not charge anything for it.
  20.  
  21.  
  22.  
  23. Table of contents
  24. -----------------
  25.  
  26. 1.  About this document
  27. 2.  Disclaimer
  28. 3.  Definition of terms
  29. 4.  Assume the following
  30. 5.  The slow method
  31. 6.  A faster method
  32. 7.  General structure of the texture mapping function
  33. 8.  Equations for the constant deltas
  34. 9.  Traditional inner loops
  35. 10. Memories from the past
  36. 11. Selfmodifying code
  37. 12. Unrolled and selfmodifying inner loops
  38. 13. Table lookup inner loops
  39. 14. Problems with precalculated runs
  40. 15. Pre-stepping texture coordinates
  41. 16. Special case code
  42. 17. Clipping
  43. 18. Clipping using matrices
  44. 19. Writing a byte, word, dword and other weird things
  45. 20. The data cache
  46. 21. The code cache
  47. 22. Some pairing rules
  48. 23. Pipeline delays
  49. 24. The time stamp counter
  50. 25. Branch prediction
  51. 26. Reference
  52. 27. Where to go from here
  53. 28. Credits and greetings
  54.  
  55.  
  56.  
  57. 1.  About this document
  58. -----------------------
  59.  
  60. This document tries to describe how to make fast affine texture mapping. The
  61. document describes both the general structure as well as the more critical
  62. parts such as inner loops. The information is aimed at both beginners and
  63. also at people who maybe already have a working texture mapper but are
  64. looking for more speed. The goal was to make a good document that would be
  65. useful today, not already be obsolete. So I'm giving you the best information
  66. I can possibly come up with.
  67.  
  68. You don't get the information for free though. You will have to invest some
  69. of your own effort and actually learn what's going on in the inner loops and
  70. select the parts that will be most suitable for you.
  71.  
  72. The information is based on my own work and findings but also on information
  73. found on the net, especially articles posted to the newsgroup
  74. comp.graphics.algorithms and on ideas given to me by other coders. IRC
  75. channel #coders is usually a good place to get new ideas and help. Many of
  76. the coders there are willing to share ideas and answer decent questions. 
  77.  
  78. I am not claiming that the methods described here are THE fastest methods of
  79. doing texture mapping. But these methods are what coders are using today and
  80. they ARE fast. 
  81.  
  82. To get the most out of this document you should have a good understanding of
  83. 386+ Assembly and C. The asm code and optimizations are aimed especially
  84. for the Intel Pentium CPU.
  85.  
  86. Note that the C code given is only meant as some sort of pseudo code. C is
  87. most of the time much easier to read that asm. For your information I have
  88. the whole texture mapping function in asm. This is overkill, I know, but this
  89. way I get full control over the optimization. In C I can only _hope_ that the
  90. compiler makes the best code possible. I'm certain that a human brain still
  91. is better to optimize code than a compiler. I do not say this because I'm a
  92. true asm-freak. In fact, I had programmed C for a year before even
  93. considering learning asm.
  94.  
  95. I should say that I do not have a masters degree in computer graphics. I'm
  96. merely a 24 year old computer and telecom engineer (B.Sc.) that found
  97. interest in this area. I have never taken any computer graphics related
  98. course in school so if you think I misuses some expressions or terms, or even
  99. leave out some expressions or terms where I should use them, you might very
  100. well be right and I wrong.
  101.  
  102. Also I have to confess that I haven't read Chris Hecker's articles in Game
  103. Developer magazine (http://www.gdmag.com). People tell me that they are good.
  104. You should probably take a look at them also.
  105.  
  106.  
  107.  
  108. 2.  Disclaimer
  109. --------------
  110.  
  111. Some parts of the technical discussion at the end of the document might not
  112. be 100% accurate as of the actual hardware in the Pentium. But from a
  113. programmers point of view the guidelines given should apply anyway.
  114.  
  115. When I state that a inner loop is e.g. 5 clock ticks per pixel, this don't
  116. mean that it will actually run at 5 clock ticks. This is just a theoretical 
  117. minimum when I assume that the instructions pair as expected and there are
  118. no cache misses and no delays writing to RAM.
  119.  
  120.  
  121.  
  122. 3.  Definition of terms
  123. -----------------------
  124.  
  125. Just so there won't be any confusion:
  126.  
  127. triangle side     Each triangle has two sides, the left side and the right
  128.                   side.
  129.  
  130. triangle edge     These makes up the outline of the triangle. Usually one
  131.                   interpolates variables along the triangle edges, both on
  132.                   the left and the right side of the triangle.
  133.  
  134. triangle section  A triangle is always made up of 3 sections. These are
  135.                   straight lines which makes up the triangle edges. When
  136.                   interpolating along the triangle edges we must calculate
  137.                   deltas for each of the 3 sections.
  138.  
  139. triangle x        The current x value of a triangle edge on the screen. There
  140.                   are two triangle x, one on the left side and one on the
  141.                   right side of the triangle. Between these is the current
  142.                   scanline.
  143.  
  144. u and v           The x and y components in the bitmap.
  145.  
  146. dudx and dvdx     Our constant deltas for u and v, du/dx and dv/dx. (constant
  147.                   texture gradients for u and v)
  148.  
  149.  
  150.  
  151. 4.  Assume the following
  152. ------------------------  
  153.  
  154. We are only drawing triangles. (This is no problem to me as 3D Studio only
  155. uses triangles anyway.) Well actually it doesn't have to be triangles, this
  156. also works on other types of polygons as long as the texture gradients are
  157. constant for the whole polygon surface.
  158.  
  159. You agree that a fractional part of 8 bit is enough for interpolating u and v
  160. on the scanlines of the triangle. Well actually a 16 bit fractional part is
  161. better but inner loops are usually much simpler to do if we only use 8 bits.
  162.  
  163. Bitmaps always has a width of 256 pixels and a maximum height of 256 pixels.
  164. In some of the inner loops we must also assume that the bitmaps are aligned
  165. on 64k.
  166.  
  167. The CPU is a Pentium and we are in 32 bit protected mode and flat memory
  168. model (TASM+WATCOM+PMODE/W).
  169.  
  170.  
  171.  
  172. 5.  The slow method
  173. -------------------
  174.  
  175. The slow method of doing texture mapping is to interpolate u and v (and
  176. triangle x) on both the left and right side of the triangle and then
  177. calculate du/dx and dv/dx for each scanline. Then interpolate u and v when
  178. drawing the scanline. To make this even slower you could first interpolate
  179. the u and v (and triangle x) on both sides of the triangle and store the
  180. values in a edge buffer. Then pick the values from the edge buffer and draw
  181. each scanline.
  182.  
  183.  
  184.  
  185. 6.  A faster method
  186. -------------------
  187.  
  188. Don't use a edge buffer as described in the slow method above. Calculate the
  189. edge deltas when you need them and interpolate along the edges at the same
  190. time you draw each scanline. It's just as simple to do it this way and a lot
  191. faster.
  192.  
  193. One important thing you should realize is that when texture mapping a
  194. triangle (or any type of polygon that has constant texture gradients), you
  195. are interpolating two variables, u and v, whose deltas are constant over the
  196. whole triangle. I repeat, the deltas are constant for the whole triangle.
  197. Make sure you understand this because this is the key to fast texture mapping
  198. (or any other type of linear shading for that matter). I guess that the
  199. correct term isn't constant deltas, rather constant gradients, but I like the
  200. term delta better.
  201.  
  202. Because the deltas (delta u and delta v) are constant, we only need to
  203. calculate them once for the whole triangle. No need to calculate them for
  204. each scanline. Also when interpolating u and v along the edges of the
  205. triangle you only need to interpolate u and v on one side of the triangle.
  206. Triangle x must be interpolated on both sides.
  207.  
  208.  
  209.  
  210. 7.  General structure of the texture mapping function
  211. -----------------------------------------------------
  212.  
  213. Here is the general structure of my texture mapping function. If you have
  214. Watcom C/C++ you can compile it as is. Just initialize VGA mode 0x13 and call
  215. it. I didn't want to include the clipping code as it only would make it more
  216. difficult to read. No kind of pre-stepping or any other type of compensation
  217. is presented here, this is just the bare bones of the function. It might look
  218. big (?) but it is pretty damn simple and efficient if I may say so myself.
  219.  
  220. You should call the function by passing a pointer to an array of 3 vertex
  221. structures and a pointer to the bitmap.
  222.  
  223.     extern char myimage[];  // 256x256 256 color bitmap
  224.     vertex array[3];
  225.     // fill in the values for each vertex in the array here
  226.     DrawTextureTriangle(array, myimage);
  227.  
  228. Note that the function doesn't move the vertex data to some local variables,
  229. it uses pointers to each of the structures instead. This makes it extremely
  230. simple to later on add more variables in the vertex structure which you will
  231. be doing in the case of an environment-bump or Phong-texture-bump mapper.
  232. The same function structure can still be used, just add a few variables to
  233. the vertex structure, calculate 2 more deltas, interpolate 2 more variables
  234. along the left side and make a new inner loop.
  235.  
  236.  
  237. // This is the only Watcom C/C++ specific part of the function. These
  238. // instructions take a 26:6 bit fixed point number and converts it 
  239. // to 32:32 bit. Then divides it with another 16:16 bit fixed point 
  240. // number. The result is 16:16 bit. This must be done in asm where we
  241. // can do 64/32 bit divides.
  242.  
  243. int shl10idiv(int x, int y);
  244. #pragma aux shl10idiv = \
  245.     " mov   edx, eax "\
  246.     " shl   eax, 10  "\
  247.     " sar   edx, 22  "\
  248.     " idiv  ebx      "\
  249.     parm [eax] [ebx] \
  250.     modify exact [eax edx] \
  251.     value [eax]
  252.  
  253. // sizeof(int) is 4
  254.  
  255. struct vertex
  256. {
  257.     int x,y;    // screen coordinates (integers)
  258.     int u,v;    // vertex u,v (26:6 bit fixed point)
  259. };
  260.  
  261. static vertex * left_array[3], * right_array[3];
  262. static int left_section, right_section;
  263. static int left_section_height, right_section_height;
  264. static int dudx, dvdx;
  265. static int left_u, delta_left_u, left_v, delta_left_v;
  266. static int left_x, delta_left_x, right_x, delta_right_x;
  267.  
  268.  
  269. inline int RightSection(void)
  270. {
  271.     vertex * v1 = right_array[ right_section ];
  272.     vertex * v2 = right_array[ right_section-1 ];
  273.  
  274.     int height = v2->y - v1->y;
  275.     if(height == 0)
  276.         return 0;
  277.  
  278.     // Calculate the deltas along this section
  279.  
  280.     delta_right_x = ((v2->x - v1->x) << 16) / height;
  281.     right_x = v1->x << 16;
  282.  
  283.     right_section_height = height;
  284.     return height;                  // return the height of this section
  285. }
  286.  
  287. inline int LeftSection(void)
  288. {
  289.     vertex * v1 = left_array[ left_section ];
  290.     vertex * v2 = left_array[ left_section-1 ];
  291.  
  292.     int height = v2->y - v1->y;
  293.     if(height == 0)
  294.         return 0;
  295.  
  296.     // Calculate the deltas along this section
  297.  
  298.     delta_left_x = ((v2->x - v1->x) << 16) / height;
  299.     left_x = v1->x << 16;
  300.     delta_left_u = ((v2->u - v1->u) << 10) / height;
  301.     left_u = v1->u << 10;
  302.     delta_left_v = ((v2->v - v1->v) << 10) / height;
  303.     left_v = v1->v << 10;
  304.  
  305.     left_section_height = height;
  306.     return height;                  // return the height of this section
  307. }
  308.  
  309. void DrawTextureTriangle(vertex * vtx, char * bitmap)
  310. {
  311.     vertex * v1 = vtx;
  312.     vertex * v2 = vtx+1;
  313.     vertex * v3 = vtx+2;
  314.  
  315.     // Sort the triangle so that v1 points to the topmost, v2 to the
  316.     // middle and v3 to the bottom vertex.
  317.      
  318.     if(v1->y > v2->y) { vertex * v = v1; v1 = v2; v2 = v; }
  319.     if(v1->y > v3->y) { vertex * v = v1; v1 = v3; v3 = v; }
  320.     if(v2->y > v3->y) { vertex * v = v2; v2 = v3; v3 = v; }
  321.  
  322.     // We start out by calculating the length of the longest scanline.
  323.  
  324.     int height = v3->y - v1->y;
  325.     if(height == 0)
  326.         return;
  327.     int temp = ((v2->y - v1->y) << 16) / height;
  328.     int longest = temp * (v3->x - v1->x) + ((v1->x - v2->x) << 16);
  329.     if(longest == 0)
  330.         return;
  331.  
  332.     // Now that we have the length of the longest scanline we can use that 
  333.     // to tell us which is left and which is the right side of the triangle.
  334.  
  335.     if(longest < 0)
  336.     {
  337.         // If longest is neg. we have the middle vertex on the right side.
  338.         // Store the pointers for the right and left edge of the triangle.
  339.         right_array[0] = v3;
  340.         right_array[1] = v2;
  341.         right_array[2] = v1;
  342.         right_section  = 2;
  343.         left_array[0]  = v3;
  344.         left_array[1]  = v1;
  345.         left_section   = 1;
  346.  
  347.         // Calculate initial left and right parameters
  348.         if(LeftSection() <= 0)
  349.             return;
  350.         if(RightSection() <= 0)
  351.         {
  352.             // The first right section had zero height. Use the next section. 
  353.             right_section--;
  354.             if(RightSection() <= 0)
  355.                 return;
  356.         }
  357.  
  358.         // Ugly compensation so that the dudx,dvdx divides won't overflow
  359.         // if the longest scanline is very short.
  360.         if(longest > -0x1000)
  361.             longest = -0x1000;     
  362.     }
  363.     else
  364.     {
  365.         // If longest is pos. we have the middle vertex on the left side.
  366.         // Store the pointers for the left and right edge of the triangle.
  367.         left_array[0]  = v3;
  368.         left_array[1]  = v2;
  369.         left_array[2]  = v1;
  370.         left_section   = 2;
  371.         right_array[0] = v3;
  372.         right_array[1] = v1;
  373.         right_section  = 1;
  374.  
  375.         // Calculate initial right and left parameters
  376.         if(RightSection() <= 0)
  377.             return;
  378.         if(LeftSection() <= 0)
  379.         {
  380.             // The first left section had zero height. Use the next section.
  381.             left_section--;
  382.             if(LeftSection() <= 0)
  383.                 return;
  384.         }
  385.  
  386.         // Ugly compensation so that the dudx,dvdx divides won't overflow
  387.         // if the longest scanline is very short.
  388.         if(longest < 0x1000)
  389.             longest = 0x1000;     
  390.     }
  391.  
  392.     // Now we calculate the constant deltas for u and v (dudx, dvdx)
  393.  
  394.     int dudx = shl10idiv(temp*(v3->u - v1->u)+((v1->u - v2->u)<<16),longest);
  395.     int dvdx = shl10idiv(temp*(v3->v - v1->v)+((v1->v - v2->v)<<16),longest);
  396.  
  397.     char * destptr = (char *) (v1->y * 320 + 0xa0000);
  398.  
  399.     // If you are using a table lookup inner loop you should setup the
  400.     // lookup table here.
  401.  
  402.     // Here starts the outer loop (for each scanline)
  403.  
  404.     for(;;)         
  405.     {
  406.         int x1 = left_x >> 16;
  407.         int width = (right_x >> 16) - x1;
  408.  
  409.         if(width > 0)
  410.         {
  411.             // This is the inner loop setup and the actual inner loop.
  412.             // If you keep everything else in C that's up to you but at 
  413.             // least remove this inner loop in C and insert some of 
  414.             // the Assembly versions.
  415.  
  416.             char * dest = destptr + x1;
  417.             int u  = left_u >> 8;
  418.             int v  = left_v >> 8;
  419.             int du = dudx   >> 8;            
  420.             int dv = dvdx   >> 8;
  421.  
  422.             // Watcom C/C++ 10.0 can't get this inner loop any tighter 
  423.             // than about 10-12 clock ticks.
  424.  
  425.             do
  426.             {
  427.                 *dest++ = bitmap[ (v & 0xff00) + ((u & 0xff00) >> 8) ];
  428.                 u += du;
  429.                 v += dv;
  430.             }
  431.             while(--width);
  432.         }
  433.  
  434.         destptr += 320;
  435.  
  436.         // Interpolate along the left edge of the triangle
  437.         if(--left_section_height <= 0)  // At the bottom of this section?
  438.         {
  439.             if(--left_section <= 0)     // All sections done?
  440.                 return;
  441.             if(LeftSection() <= 0)      // Nope, do the last section
  442.                 return;
  443.         }
  444.         else
  445.         {
  446.             left_x += delta_left_x;
  447.             left_u += delta_left_u;
  448.             left_v += delta_left_v;
  449.         }
  450.  
  451.         // Interpolate along the right edge of the triangle
  452.         if(--right_section_height <= 0) // At the bottom of this section?
  453.         {
  454.             if(--right_section <= 0)    // All sections done?
  455.                 return;
  456.             if(RightSection() <= 0)     // Nope, do the last section
  457.                 return;
  458.         }
  459.         else
  460.         {
  461.             right_x += delta_right_x;
  462.         }
  463.     }
  464. }
  465.  
  466.  
  467.  
  468. 8.  Equations for the constant deltas
  469. -------------------------------------
  470.  
  471. Sort the vertices in the triangle so that the topmost vertex is known as
  472. x1,y1 and the bottom vertex is known as x3,y3. Like the drawing below.
  473.  
  474.                                x1,y1
  475.                                 p1
  476.                                   /   
  477.                                / /    
  478.                             /   /     
  479.                          /     /      
  480.                       /       /       
  481.                    /         /        
  482.         x2,y2   /           /         
  483.         p2   /_____________/          
  484.              \    width   /          
  485.                \         /             
  486.                  \      /               
  487.                    \   /             
  488.                      \/        
  489.                    x3,y3    
  490.                     p3     
  491.  
  492.   xn,yn     - x,y screen coordinates at vertex n (integers)
  493.   pn        - Value of variable at vertex n to calculate the constant delta
  494.               for. Note that this variable is assumed to have a 6 bit
  495.               fractional part (26:6 bit fixed point). 
  496.   width     - Width of the longest scanline in the triangle
  497.  
  498.  
  499. The reason why I have p as a 26:6 bit fixed point and not 16:16 or 24:8 bit
  500. fixed point is just for being able to store u and v with a little higher
  501. precision in the 3D structure and still use only words to save space. 
  502.  
  503. Sorting 3 vertices is no more that 3 compares. Another thing: Don't load
  504. all x,y,u and v values of the vertices into registers. Use pointers to the
  505. vertex structures instead. This will also make it easier when you later on
  506. implement your Phong-texture-bump mapper. Something like this:
  507.  
  508.     ; EDX -> vertex 1
  509.     ; ESI -> vertex 2
  510.     ; EDI -> vertex 3
  511.     mov     EAX, [EDX+vertex_y]
  512.     cmp     EAX, [ESI+vertex_y]
  513.     jle     short @@sorta
  514.     xchg    EDX, ESI                ; swap v1 - v2
  515.  @@sorta:
  516.     mov     EAX, [EDX+vertex_y]
  517.     cmp     EAX, [EDI+vertex_y]
  518.     jle     short @@sortb
  519.     xchg    EDX, EDI                ; swap v1 - v3
  520.  @@sortb:
  521.     mov     EAX, [ESI+vertex_y]
  522.     cmp     EAX, [EDI+vertex_y]
  523.     jle     short @@sortc
  524.     xchg    ESI, EDI                ; swap v2 - v3
  525.  @@sortc:
  526.     ; EDX -> topmost vertex
  527.     ; ESI -> middle vertex
  528.     ; EDI -> bottom vertex
  529.  
  530.  
  531. The following two equations needs only be calculated once for all the
  532. constant deltas in the triangle. Skip the triangle if y3 == y1, i.e. if the
  533. triangle has zero height. The width can be either positive or negative
  534. depending on which side the x2,y2 vertex is. This will be useful information
  535. when sorting out which is left and which is the right side of the triangle.
  536.  
  537.               (y2-y1) << 16
  538.        temp = --------------
  539.                   y3-y1
  540.  
  541.        width = temp * (x3-x1) + ((x1-x2) << 16)
  542.  
  543. This will give you temp and width as 16:16 bit fixed point.
  544.  
  545. The equation below is used to calculate the delta for a variable that should
  546. be interpolated over the triangle, e.g. texture u. Beware of the denominator
  547. in this equation! Make sure it won't cause divide overflow in case the width
  548. is less than one pixel. (Remember that width is a 16:16 bit fixed point
  549. number.) Note that shift by 10 in the equation. This is because p1,p2,p3 has
  550. a 6 bit fractional part. The resulting delta p is a 16:16 bit number. Note
  551. that this divide should be done in asm where we can do 64/32 bit divides.
  552.  
  553.                   ( temp * (p3-p1) + ((p1-p2) << 16) ) << 10
  554.        delta p = --------------------------------------------
  555.                                  width  
  556.  
  557. So for a texture mapper where we have 2 variables (u,v) to interpolate over
  558. the triangle, we have a total of 3 divs and 3 muls to calculate dudx and
  559. dvdx.
  560.  
  561.  
  562. Here is another equation that can be used to calculate the deltas with. It
  563. was posted to the newsgroup comp.graphic.algorithm by Mark Pursey.
  564.  
  565.   There is a cleaner way, which doesn't rely on finding the widest line:
  566.   A-B-C: a triangle with screen x and y components, as well as t, a
  567.   value which could represent lightning, texture coordinates etc.
  568.   The following equation gives you the increment for t per horizontal pixel:
  569.         
  570.           (At-Ct)*(By-Cy) - (Bt-Ct)*(Ay-Cy)
  571.   dt/dx = ---------------------------------
  572.           (Ax-Cx)*(By-Cy) - (Bx-Cx)*(Ay-Cy)
  573.  
  574. I've been told that this is the correct way to calculate the deltas (or
  575. constant texture gradients). This might very well be true but the other
  576. equations gives me good results and the length of the longest scanline for
  577. free. In this equation the denominator is reusable for both u and v. This
  578. makes a total of 6 muls and 2 divs. Remember to add the necessary shifts if
  579. you do this in fixed point.
  580.  
  581.  
  582.  
  583. 9.  Traditional inner loops
  584. ---------------------------
  585.  
  586. So assuming you have come so far that you have the triangle sorted, the
  587. constant deltas calculated, the u and v deltas on the left side calculated,
  588. deltas for triangle x calculated for both sides, and you are actually
  589. interpolating those values for each scanline, we come to the very core of the
  590. texture mapper, the inner loop. I'll first present a few traditional inner
  591. loops that interpolates u and v while plotting the scanline. These loops are
  592. simple, fast and works very well. 
  593.  
  594. The loops assume the following:
  595.  
  596.  ebx     = ptr to bitmap aligned on 64k. (the low 16 bits zero)
  597.  edi     = ptr to first destination pixel to plot in this scanline
  598.  ebp     = width of scanline (loop counter)
  599.  left_u  = current u on the left edge of the triangle (16:16 bit fixed point)
  600.  left_v  = current v on the left edge of the triangle (16:16 bit fixed point)
  601.  du      = our constant delta u (24:8 bit fixed point)
  602.  dv      = our constant delta v (24:8 bit fixed point)
  603.  
  604.                                                                
  605. The first loop interpolates the u and v in two 32 bit registers (ecx, edx).
  606. We are one register short here so we use the dudx variable directly in the
  607. inner loop. This loop should run at 6 ticks per pixel. eax is not used for
  608. anything else than holding the pixel so we could unroll this loop to plot
  609. a word or dword at a time.
  610.  
  611.    mov   ecx, [left_u]              ; current u
  612.    mov   edx, [left_v]              ; current u
  613.    shr   ecx, 8                     ; make them 28:8 bit fixed point
  614.    shr   edx, 8             
  615.    mov   bl, ch                     ; make ebx point to the first textel
  616.    mov   bh, dh
  617.    mov   esi, [du]
  618.  
  619.  @@inner:
  620.     add   edx, [dv]                 ; update v
  621.     add   ecx, esi                  ; update u
  622.     mov   al, [ebx]                 ; get pixel from aligned texture map
  623.     mov   bl, ch
  624.     mov   [edi], al                 ; plot pixel
  625.     mov   bh, dh
  626.     inc   edi
  627.     dec   ebp
  628.     jnz   @@inner
  629.  
  630.  
  631. Just to show that it is also possible to directly interpolate u and v in ebx
  632. I'll present this one that uses the carry flag to add the "overflow" from the
  633. fractional part to the whole part of u and v.
  634.  
  635.     mov   cl, byte ptr [left_u+1]   ; fractional part of current u
  636.     mov   ch, byte ptr [left_v+1]   ; fractional part of current v
  637.     mov   dl, byte ptr [du]         ; fractional part of delta u
  638.     mov   dh, byte ptr [dv]         ; fractional part of delta v
  639.     mov   bl, byte ptr [left_u+2]   ; whole part of current u
  640.     mov   bh, byte ptr [left_v+2]   ; whole part of current v
  641.  
  642.  @@inner:
  643.     mov   al, [ebx]                 ; get pixel from aligned texture map
  644.     add   cl, dl                    ; update fractional part of u
  645.     adc   bl, byte ptr [du+1]       ; + whole part of dudx (+carry)
  646.     add   ch, dh                    ; update fractional part of v
  647.     adc   bh, byte ptr [dv+1]       ; + whole part of dvdx (+carry)
  648.     mov   [edi], al                 ; plot pixel
  649.     inc   edi
  650.     dec   ebp
  651.     jnz   @@inner
  652.  
  653.  
  654. The following loop uses a combination of interpolation in one 32 bit register
  655. (ecx) and the carry overflow method. We have just enough registers in this
  656. loop that we don't need to use any memory variables. On the other hand this
  657. makes it impossible to unroll it and plot a word or dword at a time. Anyway, 
  658. this version should run at 5 ticks per pixel.
  659.  
  660.     mov   ecx, [left_u]
  661.     shr   ecx, 8                    ; make it 28:8 bit fixed point
  662.     mov   esi, [du]
  663.     mov   dl, byte ptr [dv]         ; fractional part of delta v 
  664.     mov   dh, byte ptr [left_v+1]   ; fractional part of current v
  665.     mov   ah, byte ptr [dv+1]       ; whole part of delta v
  666.     mov   bh, byte ptr [left_v+2]   ; whole part of current v
  667.     mov   bl, ch
  668.  
  669.  @@inner:
  670.     add   ecx, esi                  ; update u
  671.     mov   al, [ebx]                 ; get pixel from aligned texture map
  672.     mov   bl, ch
  673.     add   dh, dl                    ; update fractional part of v
  674.     adc   bh, ah                    ; + whole part of of delta v (+carry)
  675.     mov   [edi], al                 ; plot pixel
  676.     inc   edi
  677.     dec   ebp
  678.     jnz   @@inner
  679.  
  680. The loop counter (ebp) in the above loop can be removed if we reorder the
  681. registers a bit and plot the scanline from right to left. 
  682.  
  683.  @@inner:
  684.     add   ecx, ebp
  685.     mov   al, [ebx]
  686.     mov   bl, ch
  687.     add   dh, dl
  688.     adc   dh, ah
  689.     mov   [edi+esi], al
  690.     dec   esi
  691.     jnz   @@inner
  692.  
  693. The loop should now run at 4 clock ticks.
  694.  
  695. I'm sure there are other ways to make these kind of loops but this is what I
  696. could come up with.
  697.  
  698. After I wrote the above sentence, there was a post in the newsgroup
  699. comp.graphics.algorithms by Sean L. Palmer where he presented the following
  700. 4 tick loop:
  701.     
  702.     Texture must be aligned on a 64K boundary. Must be 256x256.
  703.     Only 8 bits used for fractions, means shaky textures.
  704.     Start at right end of scanline
  705.     
  706.     T=texture adr        
  707.     D=dest adr+count (start)
  708.     E=dest adr (end)
  709.     X=tex X int          (whole part of initial u)
  710.     x=tex X frac         (fractional part of initial u)
  711.     Y=tex Y int          (whole part of initial v)
  712.     y=tex Y frac         (fractional part of initial v)
  713.     H=tex X step int     (whole part of delta u)
  714.     h=tex X step frac    (fractional part of delta u)
  715.     V=tex Y step int     (whole part of delta v)
  716.     v=tex Y step frac    (fractional part of delta v)
  717.     m=account for borrow for negative Y step, either 0 or 0FFh
  718.     p=texture pixel
  719.     
  720.     edi=DDDD
  721.     esi=EEEE
  722.     edx=TTYX
  723.     eax=000p
  724.     ebx=x0Yy
  725.     ecx=hmVv
  726.     ebp=000H
  727.     esp=
  728.     
  729.       mov   dh,bh
  730.     @@L:
  731.       mov   al,[edx]
  732.       add   ebx,ecx
  733.       adc   edx,ebp
  734.       dec   edi
  735.       mov   dh,bh
  736.       cmp   edi,esi
  737.       mov   [edi],al
  738.       jne   @@L
  739.         
  740. It's not necessary to simulate the loop counter this way. esi is not really
  741. used in the loop so we might as well use it as a loop counter and draw the
  742. scanline from left to right (the way I like to draw my scanlines). Like this:
  743.  
  744.   @@inner:
  745.     mov   al, [edx]
  746.     add   ebx, ecx
  747.     adc   edx, ebp
  748.     inc   edi
  749.     mov   dh, bh
  750.     dec   esi
  751.     mov   [edi], al
  752.     jnz   @@inner
  753.  
  754. Both of these loops uses eax only to hold the pixel so they can be unrolled
  755. to plot a word or dword at a time. In fact, by unrolling this loop to plot
  756. a dword per turn it might very well beat the table lookup inner loop
  757. presented below. By unrolling this loop we can remove 3 instructions,
  758. "inc edi", "dec esi" and "jnz @@inner". This will also mean that the loop
  759. will become too tight that will lead to AGI delays instead.
  760.  
  761.  
  762.  
  763. 10. Memories from the past
  764. --------------------------
  765.  
  766. I as many others, started coding asm in real mode and later on moved to
  767. protected mode and flat model. The thing I miss about real mode was the
  768. ability to have a pointer in the low 16 bit and a variable in the high 16 bit
  769. of a 32 bit register. In flat model we need all 32 bits for the pointer.
  770. Sure, one can setup a selector and address the data with only the low 16 bits
  771. but all prefix bytes can be seen as a 1 clock tick, nonpairable instruction
  772. on the Pentium. So addressing with only 16 bit and using a segment override 
  773. will give 2 prefix bytes or 2 ticks delay.
  774.  
  775. The following loop in real mode was for a bitmap scaler I once used. We have
  776. 4 variables in only 2 registers (edi, ebx). 
  777.  
  778.     ; ebx = neg(loop counter)   : source ptr 
  779.     ; edi = decision variable   : destination pointer
  780.     ; ecx = frac. part of delta : 1
  781.     ; edx = 1                   : whole part of delta
  782.     ; the delta is 16:16 bit 
  783.  @@inner:
  784.     mov   al, [bx]
  785.     mov   es:[di], al
  786.     add   edi, ecx      ; update fractional part : move dest. pointer
  787.     adc   ebx, edx      ; update loop counter    : whole step in bmp (+carry)
  788.     jnc   @@inner       ; jump if loop counter didn't overflow
  789.  
  790. OK, this loop is crap on a Pentium but ain't it pretty? Just two adds to move
  791. both pointers, update the decision variable and loop counter. If we only had
  792. 64 bit registers on the Pentium...
  793.  
  794.  
  795.  
  796. 11. Selfmodifying code
  797. -----------------------
  798.  
  799. One way to get rid of the memory variables in inner loops is to use
  800. selfmodifying code. When you have calculated a constant delta and are about
  801. to store it in a memory variable, why don't you store it right into a
  802. instruction as a constant in the inner loop? It's just as simple. Just
  803. remember to not use CS as segment override as we are in protected mode.
  804.  
  805. I must warn you about this way of coding, especially on the Pentium (read
  806. about the code cache at the end). It can actually make the loop slower even
  807. if you think you cut away a few ticks.
  808.  
  809. Doing more complex shadings like environment-bump or Phong-texture-bump,
  810. selfmodifying code might be the only way to get it to run at all. I.e. not
  811. having to write to any memory variables from the inner loop. If you are about
  812. to make your loop selfmodifying, compare it with your old loop by actually
  813. timing a typical scene. Then you'll know if you gained anything.
  814.  
  815. If your loop is faster with selfmodifying code and the environment your
  816. application is aimed for allows selfmodifying code, I'd definitely say go for
  817. it, use selfmodifying code.
  818.  
  819.  
  820.  
  821. 12. Unrolled and selfmodifying inner loops
  822. ------------------------------------------
  823.  
  824. I don't really see these as an alternative to the traditional inner loops on
  825. the Pentium. I present them here just because they are interesting.
  826.  
  827. The deltas are constant so the offsets for each pixel in each scanline into
  828. the bitmap will also be constant. I.e. we can precalculate a whole run and
  829. use that in the inner loop. The inner loops for these type of texture mappers
  830. can look very different. The most radical must be to unroll it all the way
  831. and to plug in the offsets right into the mov instructions, i.e.
  832. selfmodifying code. These completely unrolled loops will be pretty big also.
  833. The loop below is 14 byte per pixel which means over 4k code for a whole 320
  834. pixel scanline. The loop will take up half of the code cache. Ouch! (read
  835. about the code cache at the end). Here is some code that shows the principle
  836. of this type of "inner loop":
  837.  
  838.     jmp   ecx                   ; Jump to the right place in the "loop"
  839.     mov   al, [esi+12345]
  840.     mov   [edi+319], al
  841.     mov   al, [esi+12345]       ; Get pixel 
  842.     mov   [edi+318], al         ; Plot pixel
  843.     ......
  844.     mov   al, [esi+12345]       ; '12345' is the selfmodifying part
  845.     mov   [edi+2], al           ; that will be modified once per triangle
  846.     mov   al, [esi+12345]
  847.     mov   [edi+1], al
  848.     mov   al, [esi+12345]
  849.     mov   [edi+0], al
  850.  
  851. Note that we are doing it backwards, from right to left. This makes it easier
  852. to setup esi and edi. As the code for each pixel in this loop is 14 byte you
  853. will be doing a X*14 when calculating the jump offset. X*14 is (X<<4)-X-X.
  854. You should of coarse not plug in the offsets for the whole loop if you only
  855. have a small triangle. The length of the longest scanline is a byproduct from
  856. the constant delta calculations.
  857.  
  858.  
  859. So what about the 1.5 tick per pixel loop?
  860. Well the following peace of code is usually what people think of. I'm not
  861. really sure that this is actually 1.5 tick per pixel as the 'mov [edi+?],ax' 
  862. has a operand size prefix byte. This code will need some work to make the
  863. instructions pair on the Pentium. Of coarse this loop also suffers from the
  864. same problems as the previous selfmodifying, unrolled loop.
  865.  
  866.     jmp   ecx
  867.     ......
  868.     mov   al, [esi+12345]
  869.     mov   ah, [esi+12345]
  870.     mov   [edi+4], ax
  871.     mov   al, [esi+12345]
  872.     mov   ah, [esi+12345]
  873.     mov   [edi+2], ax
  874.     mov   al, [esi+12345]
  875.     mov   ah, [esi+12345]
  876.     mov   [edi], ax
  877.  
  878.  
  879.  
  880. 13. Table lookup inner loops
  881. ----------------------------
  882.  
  883. Now to a cooler method that is not selfmodifying and don't need to be
  884. unrolled all the way. The idea is very similar to the unrolled loops above
  885. but in this loop we have the offsets stored in a lookup table instead. For
  886. each pixel we get the address of the next pixel from the lookup table. This
  887. method should be much more Pentium friendly. Also this inner loop don't need
  888. to have the bitmap aligned on 64k as the traditional inner loops.
  889.  
  890. The loop assume the following:
  891.  
  892.  esi     = ptr to bitmap (no alignment needed)
  893.  edi     = ptr to first destination pixel to plot in this scanline
  894.  ebp     = width of scanline (loop counter)
  895.  left_u  = current u on the left edge of the triangle (16:16 bit fixed point)
  896.  left_v  = current v on the left edge of the triangle (16:16 bit fixed point)
  897.  lookup  = ptr to the precalculated lookup table. The lookup table is an
  898.            array of dwords.
  899.  
  900.  
  901.     mov   edx, [lookup]
  902.     xor   eax, eax
  903.     mov   al, byte ptr [left_u+2]
  904.     mov   ah, byte ptr [left_v+2]
  905.     add   esi, eax
  906.  
  907.   @@inner:
  908.     mov   al, [esi+ebx]         ; Get pixel
  909.     mov   ebx, [edx]            ; Get offset for next pixel
  910.     mov   [edi], al             ; Plot pixel
  911.     add   edx, 4
  912.     inc   edi
  913.     dec   ebp
  914.     jnz   @@inner
  915.  
  916.  
  917. The same loop could look like this in C:
  918.  
  919.     // destptr = ptr to screen + y*320
  920.     // bitmap  = ptr to bitmap
  921.     // lookup  = ptr to lookup table
  922.     // x1      = start screen x coordinate of scanline
  923.     // width   = width of scanline
  924.  
  925.     char * dest = destptr + x1;
  926.     char * src  = bitmap + (left_u>>16) + (left_v>>16)*256;
  927.  
  928.     for(; width--; )
  929.     {
  930.         *(dest++) = src[ *(lookup++) ];            
  931.     }
  932.  
  933.  
  934. The above loop in asm should be 4 clock ticks per pixel on a Pentium. This
  935. loop can be changed to plot 4 pixels at a time:
  936.  
  937.   @@inner:
  938.     mov   al, [esi+ebx]         ; Get pixel #1
  939.     mov   ebx, [edx]          
  940.     mov   ah, [esi+ecx]         ; Get pixel #2
  941.     mov   ecx, [edx+4]         
  942.     shl   eax, 16               ; Move pixels 1 and 2 to the high word
  943.     add   edi, 4
  944.     mov   al, [esi+ebx]         ; Get pixel #3
  945.     mov   ebx, [edx+8]
  946.     mov   ah, [esi+ecx]         ; Get pixel #4
  947.     mov   ecx, [edx+12]          
  948.     rol   eax, 16               ; Swap the high and low words
  949.     add   edx, 16
  950.     mov   [edi], eax            ; Plot all 4 pixels
  951.     dec   ebp
  952.     jnz   @@inner
  953.  
  954. Now this loop is 9 (8 if we assume that shl and rol are pairable in the U
  955. pipeline) ticks per 4 pixel with the pixels written as a dword. Very
  956. good if we align the write on dword. Use the other loop for very short lines
  957. or to get this one aligned on dword and use this for the rest of the
  958. scanline.
  959.  
  960.  
  961. Calculate the lookup table with the following loop (this loop can also be
  962. used to calculate the offsets in the selfmodifying example):
  963. (dudx and dvdx are 16:16 bit fixed point. lookup is an array of dwords)
  964.  
  965.    int du = dudx >> 8; 
  966.    int dv = dvdx >> 8;
  967.    int u = 0;
  968.    int v = 0; 
  969.    for( width of longest scanline )
  970.    {
  971.       *lookup++ = (u>>8) + (v & 0xffffff00);
  972.       u += du;
  973.       v += dv;
  974.    }
  975.  
  976.    ; ebx = ecx = 0
  977.    ; esi = delta u  (26:8 bit fixed point)
  978.    ; edi = delta v  (26:8 bit fixed point)
  979.    ; edx = ptr to lookup table
  980.    ; ebp = length of table (the width of the longest scanline)
  981.  
  982.  @@mklookup:
  983.     mov   eax, ecx          
  984.     add   ecx, edi          ; update v
  985.     mov   al, bh
  986.     add   ebx, esi          ; update u
  987.     mov   [edx], eax        ; lookup[edx] = u+256*v
  988.     add   edx, 4
  989.     dec   ebp
  990.     jnz   @@mklookup
  991.  
  992.  
  993.  
  994. 14. Problems with precalculated runs
  995. ------------------------------------
  996.  
  997. The more I play around with inner loops that uses the same precalculated run
  998. for each scanline, the more skeptic I get. This is because they all suffers
  999. from the same problem, no matter if we use a lookup table or if we have a
  1000. unrolled selfmodified loop.
  1001.  
  1002. In the case of the lookup table inner loop we always start at the beginning
  1003. of the table when drawing a scanline. This is wrong and will give very bad
  1004. distortion especially when the triangle is zoomed in close. Always starting
  1005. at the beginning of the table is the same as ignoring the fractional parts of
  1006. the initial u and v of the scanline. So to fix this we should start somewhere
  1007. into the table depending on the initial fractional parts of u and v. But this
  1008. is impossible because u and v are interpolated separately on the triangle
  1009. edge but are fixed to each other in the lookup table. Wilco Dijkstra posted
  1010. the following solution in comp.graphics.algorithms:
  1011.  
  1012.  
  1013.     The basic idea is correct. What you mean is using subpixel positioning
  1014.     with one or two bits precision. For example, for 2 bits subpixel
  1015.     positioning you have to create 4 * 4 tables of the longest scanline.
  1016.     The first table starts at u = v = 0, second u = 0, v = 0.25, third u  0,
  1017.     v = 0.50 fourth u = 0, v = 0.75, fifth u = 0.25, v = 0, etc.
  1018.     When stepping down the scanlines, select the table giving the 2 most
  1019.     significant fractional bits of u and v. The maximum error you get is 1/8
  1020.     in each direction (when proper rounding is used!). Thus this is 64 times
  1021.     more precise than using no subpixel positioning.
  1022.     
  1023.     The problem is that it's only faster for very large triangles (eg. more
  1024.     than 32 scanlines deep), so it may be faster (and more accurate) to draw
  1025.     the texture in the standard way, without a table.
  1026.  
  1027.  
  1028. This method will reduce the distortion. On the other hand the lookup tables
  1029. will require much more memory that in turn will push out other cached data,
  1030. not to mention the additional time it takes to setup the tables. 
  1031.  
  1032.  
  1033.  
  1034. 15. Pre-stepping texture coordinates
  1035. ------------------------------------
  1036.  
  1037. When we interpolate u, v and triangle x along the left edge of the triangle
  1038. we always truncates triangle x when drawing a scanline. This is natural
  1039. because we can only draw whole pixels. When we truncates x we must also
  1040. adjust the initial u and v of the scanline. Adjusting u and v will give much
  1041. cleaner and stable textures. Note that this only applies if you use a
  1042. traditional inner loop. Don't bother doing this if you are using a table
  1043. lookup inner loop.  Kevin Baca sent me the following explanation:
  1044.  
  1045.  
  1046.     No matter how you compute screen pixels, you need to "pre-step" your
  1047.     texture coordinates by the difference between actual screen  coordinates
  1048.     and screen pixels.  It looks like this:
  1049.     
  1050.     // sp = screen pixel, sc = screen coordinate.
  1051.     float sc, diff, u, v, dudx, dvdx;
  1052.     int sp;
  1053.     
  1054.     sp = (int) sc;
  1055.     diff = sc - (float) sp;
  1056.     u -= dudx * diff;
  1057.     v -= dvdx * diff;
  1058.     
  1059.     You can actually do this without multiplies (by calculating a dda for 
  1060.     each edge that determines when to add an extra 1 to the texel 
  1061.     coordinates).
  1062.     
  1063.  
  1064.  
  1065. 16. Special case code
  1066. ---------------------
  1067.  
  1068. It often pays off to make special case code that takes care of the edge delta
  1069. calculations when a triangle section is 1, 2 or 4 pixels high. Then you can
  1070. skip the divs and use shifts instead. 
  1071.  
  1072. I once made a histogram of the length of each scanline in the very popular
  1073. chrmface.3ds object. This object has about 850 triangles and was scaled up
  1074. so it just touched the top and the bottom of a 320x200 pixel screen. The
  1075. histogram showed that most scanlines was only 1 or 2 pixels wide. This proves
  1076. that the outer loop is just as important as the inner loop and also that it
  1077. might be a good idea to have special case code for those 1 or 2 pixel lines.
  1078.  
  1079. width    number of scanlines
  1080.   1     *********************
  1081.   2     ******************
  1082.   3     **********
  1083.   4     ******
  1084.   5     ***
  1085.   6     **
  1086.   7     **
  1087.  
  1088.  
  1089.  
  1090. 17. Clipping
  1091. ------------
  1092.  
  1093. Clipping is most of the time a real pain in the ass implementing. It will
  1094. always mess up a nice looking routine with extra junk. One possibility is to
  1095. have two separate functions, one with clipping and one with no clipping. Then
  1096. test the triangle if it needs clipping before calling any of the functions.
  1097.  
  1098. The actual clipping code is not that difficult to implement really. Say if
  1099. you need to clip a texture mapped scanline, you first have to get the number
  1100. of pixels you need to skip at the end of the scanline and the number of
  1101. pixels in the beginning of the scanline. Then subtract the number of pixels
  1102. skipped from the original scanline width. If you skipped some pixels at the
  1103. start of the scanline, the new starting u and v must be calculated. This is
  1104. done by multiplying the pixels skipped by delta u and delta v respectively.
  1105. And adding the original starting u and v of coarse.
  1106.  
  1107. The following code is what I'm using to sort out the stuff:
  1108.  
  1109.     movsx   EBP, word ptr [left_x+2]    ; Get the integer part from the
  1110.     movsx   ECX, word ptr [right_x+2]   ; 16:16 bit numbers.
  1111.     mov     EDX, EBP
  1112.     sub     EDX, ECX
  1113.     ; EDX = width of scanline
  1114.     ; ECX = x1
  1115.     ; EBP = x2
  1116.     mov     EBX, EDX
  1117.     sub     EBP, [_RightClip]
  1118.     jle     short @@rightok
  1119.     sub     EDX, EBP                    ; skip pixels at end
  1120.  @@rightok:
  1121.     xor     EAX, EAX
  1122.     cmp     ECX, [_LeftClip]
  1123.     jge     short @@leftok
  1124.     mov     EAX, [_LeftClip]
  1125.     sub     EAX, ECX
  1126.     mov     ECX, [_LeftClip]
  1127.  @@leftok:
  1128.     sub     EDX, EAX                    ; skip pixels at start
  1129.     jle     @@notvisible
  1130.     ; EAX = pixels skipped at start
  1131.     ; ECX = clipped x1
  1132.     ; EDX = clipped width of scanline
  1133.  
  1134. So now you just have to multiply EAX by delta u and add the original u to get
  1135. the clipped u. The same apply for v.
  1136.  
  1137.  
  1138.  
  1139. 18. Clipping using matrices
  1140. ---------------------------
  1141.  
  1142. I've been told that clipping should not be done scanline by scanline in the
  1143. texture mapping function. But I have yet to find a simple alternative
  1144. solution to this. Don't confuse the clipping I'm referring to with removal of
  1145. nonvisible polygons. When we arrive at the texture mapping function we should
  1146. already have removed those triangles that are backface or outside the
  1147. viewcone.
  1148.  
  1149. Kevin Baca sent me the following explanation on how to decide if vertices
  1150. should be clipped or not.
  1151.  
  1152.  
  1153.     If you use homogeneous matrices to do your transformations
  1154.     it's actually very simple to clip before you do the perspective 
  1155.     divide to get screen coordinates.
  1156.     
  1157.     Using homogeneous coordinates, you get vertices of the form [X Y Z W] 
  1158.     after doing the perspective projection.  To get actual screen 
  1159.     coordinates, you divide X and Y by W.  If you are going to 
  1160.     "Normalized Device Coordinates" the results of these divisions will 
  1161.     be -1 < X' < 1 and -1 < Y' < 1.  Therefore, to do clipping you need 
  1162.     to perform the following comparison before the perspective divide:
  1163.     
  1164.     -W < X < W, -W < Y < W.
  1165.     
  1166.     To clip along the Z axis, you can do the same thing, but I usually 
  1167.     use the following comparison instead:
  1168.     
  1169.     0 < Z < W.
  1170.     
  1171.     To do a perspective projection, multiply the projection matrix, P, by 
  1172.     the view matrix, V:  M = P * V.
  1173.     
  1174.     The view matrix is the result of all your transformations 
  1175.     (translations, rotations, scalings, etc.) of both the model and the 
  1176.     camera.  For the projection matrix, I use the following:
  1177.     
  1178.     1  0  0  0
  1179.     0  a  0  0
  1180.     0  0  b  c
  1181.     0  0  f  0
  1182.     
  1183.     where:
  1184.     a = the aspect ratio (width / height of screen)
  1185.     b = f * (yon / (yon - hither))
  1186.     c = -f * (yon * hither / (yon - hither))
  1187.     f = sin(aov / 2) / cos(aov / 2)
  1188.     aov = angle of view
  1189.     yon = distance to far clipping plane
  1190.     hither = distance to near clipping plane
  1191.     
  1192.     These values allow me to clip using:
  1193.     -W < X < W
  1194.     -W < Y < W
  1195.     0 < Z < W
  1196.     
  1197.     After clipping, divide X and Y by W and multiply by the width and 
  1198.     height of your screen to get final screen coordinates.
  1199.  
  1200.  
  1201.  
  1202. 19. Writing a byte, word, dword and other weird things
  1203. ------------------------------------------------------
  1204.  
  1205. Now to a weird thing on the Pentium. The Pentium has a so called Write-Back
  1206. cache. Well, the fact that the Pentium has a Write-Back cache is not weird at
  1207. all. It's how the Write-Back cache works in practice that is weird if you are
  1208. used to a Write-Trough cache that is used on the 486.
  1209.  
  1210. Write-Trough:
  1211.     When we write a byte to memory the byte is always written to RAM. If that 
  1212.     same byte is also present in the cache, the byte in the cache is also 
  1213.     updated.
  1214.     
  1215. Write-Back:
  1216.     When we write a byte to memory the byte is only written to RAM if the
  1217.     same byte is not present in the cache. If the byte is present in the
  1218.     cache, only the cache will be updated. It is first when a cacheline is
  1219.     pushed out from the cache that the whole cacheline will be written to
  1220.     RAM.
  1221.  
  1222. I have done tests on my system (Pentium 120, L1:8+8k, L2:256k) using the
  1223. time stamp counter to see how it actually behaves. These are the results:
  1224.  
  1225. Writing to a byte (or aligned word or dword) that is not present in the L1
  1226. cache takes 8 clock ticks (no matter if the byte is present in the L2 cache).
  1227. If the byte is present in the L1 cache, the same "mov" instruction takes the
  1228. theoretical 0.5 clock tick.
  1229.  
  1230. This is very interesting and potentially useful. If we e.g. manage to keep
  1231. the cacheline where we have our memory variables in the L1 cache, we can
  1232. write to them at the same speed as writing to a register. This could be very
  1233. useful in the case of a Phong-texture or Phong-texture-bump inner loop where
  1234. we need to interpolate many variables and only have 7 registers.
  1235.  
  1236. The problem is that our cacheline will be pushed out from the cache as soon
  1237. as we start getting cache misses when reading the texture data. Then we are
  1238. back at 8 clock tick per write. To fix this we must read a byte from our
  1239. cacheline so that it won't be marked as old and thrown out. But this is
  1240. usually what we do anyway. We read a variable, interpolates it, uses it and
  1241. writes it back.
  1242.  
  1243. Juan Carlos Arevalo Baeza presented in an article to comp.graphics.algorithms
  1244. another way to make use of the Write-Back cache in a texture mapping inner
  1245. loop. The idea is to ensure that the destination pixel written is always
  1246. present in the cache. This is done by reading a byte from the destination
  1247. cacheline first:
  1248.  
  1249.      ; edi = ptr to first destination pixel (+1) to plot
  1250.      ; esi = ptr to last destination pixel to plot
  1251.      ; The scanline is plotted from right to left
  1252.  
  1253.       push esi
  1254.       mov  al,[edi-1]    ; read the first byte into the cache.
  1255.     
  1256.     @@L1:
  1257.       lea  esi,[edi-32]
  1258.       cmp  esi,[esp]
  1259.       jae  @@C
  1260.       mov  esi,[esp]
  1261.     @@C:
  1262.       mov  al,[esi]      ; read the last byte of the 32-byte chunk.
  1263.     @@L:
  1264.       mov  al,[edx]
  1265.       add  ebx,ecx
  1266.       adc  edx,ebp
  1267.       dec  edi
  1268.       mov  dh,bh
  1269.       cmp  edi,esi
  1270.       mov  [edi],al
  1271.       jne  @@L
  1272.     
  1273.       cmp  edi,[esp]
  1274.       jne  @@L1
  1275.     
  1276.       pop  esi
  1277.  
  1278.     This ensures that whenever you write a pixel, that address is already in
  1279.     the cache, and that's a lot faster. A LOT. My P90 takes 20-40 cycles to
  1280.     read a cache line, so that's around 1 more cycle per pixel. Problems:
  1281.     when painting polys, rows of very few pixels (let's say 1-8 pixels) are
  1282.     the most common, and those don't feel so good about this loop. You can
  1283.     always have two loops for the different lengths.
  1284.  
  1285.  
  1286. Another way to speed up writes (that also works on 486) is to collect 4
  1287. pixels in a 32 bit register and write all 4 pixels at a time as a aligned
  1288. dword. This will split the 8 clock tick delay on all 4 pixels making the
  1289. delay only 2 clock ticks per pixel. This method will almost always gain speed
  1290. especially if the scanlines are long.
  1291.  
  1292.  
  1293.  
  1294. 20. The data cache
  1295. ------------------
  1296.  
  1297. Although it is fun optimizing inner loops there are other important factors
  1298. that one should look at. With the Pentium processor the cache aspects are
  1299. very important. Maybe more important than the speed of the inner loop. Don't
  1300. know how long this is true though as newer processors seems to get bigger and
  1301. bigger caches that probably will become smarter also.
  1302.  
  1303. The general idea of the cache is:
  1304. When the CPU has decoded an instruction that needs to get a variable from
  1305. memory, the CPU first checks the cache to see if the variable is already
  1306. in the cache. If it is there the CPU reads the variable from the cache.
  1307. This is called a cache hit. If the variable is not in the cache the CPU first
  1308. has to wait for the data to be read from RAM (or the secondary cache, L2)
  1309. into the cache and first after that get the variable from the cache. The
  1310. cache always loads a full cacheline at a time so this will take a few clock
  1311. ticks. A cacheline is 16 byte on a 486 and 32 byte on Pentium. The advantage
  1312. of this is when reading byte after byte from the memory, the data will most
  1313. of the time already be loaded into the cache because we have accessed the
  1314. same cacheline just before. Also a cacheline is always aligned on 16 byte
  1315. on the 486 and on 32 byte on the Pentium.
  1316.  
  1317. I did a few tests on my system (Pentium 120 MHz, L1 cache 8+8k, L2 cache
  1318. 256k) using the time stamp counter to check the actual time for loading a
  1319. cacheline. In the first test I flushed the L2 cache so that each cacheline
  1320. must be read all the way from RAM. This was done by allocating a 256k memory
  1321. chunk and read each byte of that first. This would cause the memory I did the
  1322. test on to be pushed out of the L2 cache. The testloop looked like this:
  1323.  
  1324.     mov  ecx, 1000
  1325.   next:
  1326.     mov  al, [esi]
  1327.     add  esi, ofs
  1328.     dec  ecx
  1329.     jnz  next
  1330.  
  1331. The overhead of the loop was first timed by replacing the "mov al, [esi]"
  1332. by "mov al, cl". The loop ran at exactly 2 clock tick per turn. The "ofs"
  1333. value was replaced for each run with 1, 2, 4, 8, 16, 32, 64, ... In the
  1334. second test I first forced the L2 cache to load the memory by reading each
  1335. byte of a 128k memory chunk and then run the testloop on the same memory.
  1336. Here are the results of both tests:
  1337.  
  1338.  
  1339.  clock ticks
  1340.                                                               * *
  1341.     |                                          *  *  *  *  *
  1342.  40 +                              *  *  *  *  
  1343.     |                             *
  1344.  35 +                   from RAM *
  1345.     |                           *
  1346.  30 +                          *
  1347.     |                          *
  1348.  25 +                         *
  1349.     |                        *
  1350.  20 +                       *      +  +  +  +  +  +  +  +  +  + +
  1351.     |                      *      +
  1352.  15 +                     *     +
  1353.     |                   *      +  from L2 cache
  1354.  10 +                  *     +
  1355.     |                 *   +
  1356.   5 +               *  +
  1357.     |            * +
  1358.   0 + -----+-----+-----+-----+-----+-----+-----+-----+-----+-----  ofs
  1359.     1      2     4     8    16    32    64    128   256   512     
  1360.  
  1361.  
  1362. So this tells me that it takes 40-45 clock ticks minimum to load a cacheline
  1363. all the way from RAM and exactly 18 clock ticks from the L2 cache. When "ofs"
  1364. was 1 the "mov al, [esi]" ran at 2.0 ticks when loading from RAM and 1.1
  1365. ticks from the L2 cache. 0.5+40/32=1.75 and 0.5+18/32=1.06 so this makes
  1366. sense.
  1367.  
  1368. This is pretty scary!  18 clock ticks to load a cacheline from the L2 cache.
  1369. 18 clock ticks minimum for the inner loops if we assume that a cacheline must
  1370. be filled for each byte read. Ouch!
  1371.  
  1372. So in the case of a texture mapper where we might be reading texels in a
  1373. vertical line in the bitmap, the inner loop will be accessing pixels that
  1374. are >256 bytes apart. The CPU will then be busy filling cachelines for each
  1375. texel. A 64k bitmap won't fit inside a 8k cache, you know. So what can we do?
  1376. Well, we can wait on Intel to invent bigger caches or we might consider
  1377. storing our bitmaps some other, more cache friendly way.
  1378.  
  1379. I got an interesting tip from Otto Chrons on channel #coders the other day
  1380. about this. He said that one should store the bitmap as a set of tiles, say
  1381. 8 x 8 pixels instead of the usual 256 x 256 pixel. This makes perfect sense.
  1382. It would mean that a small part of the bitmap (8 x 4 pixel) would fit in the
  1383. same 32 byte cacheline. This way, new cachelines don't need to be loaded that
  1384. often when reading pixels in a vertical line in the bitmap.
  1385.  
  1386. The following was suggested in a mail to me by Dare Manojlovic:
  1387.  
  1388.  
  1389.     If you are saving bitmap as a set of tiles (8*4) the inner loop wouldn't
  1390.     have to be more complicated (this is my opinion - not yet tested).
  1391.     
  1392.     For example, let's say that we have u&v texture coordinates, we only have
  1393.     to reorder bits to get the correct address (before the inner loop):
  1394.        Normally for a bitmap of 256*256 the texel address would look like:
  1395.        EAX                           AH            AL
  1396.         oooo oooo    oooo oooo    oooo oooo     oooo oooo
  1397.                                 v coordinate   u coordinate
  1398.     
  1399.        And now:
  1400.        EAX                           AH            AL
  1401.         oooo oooo    oooo oooo    oooo oooo    oooo oooo
  1402.          v(other 6 bits)  u(other 5 bits) v(lower 2 bits) u(lower 3 bits)
  1403.  
  1404.     Adding a constant value,that is also converted, in the loop shouldn't be
  1405.     a problem.
  1406.  
  1407.     Now, as I understand cache loading procedure,it always loads 32 bytes of
  1408.     data (Pentium), so the whole bitmap tile of (8*4 pixels) will be in cache.
  1409.     Of course bitmap tile must be 32 bytes aligned.
  1410.     This would also work faster on 486 where cache is loaded with 16 bytes.
  1411.  
  1412.  
  1413. There is a small problem to the above method. We can't just add a constant
  1414. value to a number in this format (even if they both are converted). This
  1415. is because there is a gap between the bits. We must make the bits jump over
  1416. the gap to make the add correct. There is a simple solution to this problem
  1417. though. Just fill the gap with 1:s before adding the constant value. This
  1418. will cause the bit to jump over the gap. Filling the gap is done with a
  1419. bitwise OR instruction.
  1420.  
  1421. Converting u and v (16:16 bit) to this format can be done with the following
  1422. code:
  1423.  
  1424.     int uc = (u & 0x0007ffff) | ((u<<2) & 0xffe00000);
  1425.     int vc = (v & 0x0003ffff) | ((v<<5) & 0xff800000);
  1426.  
  1427.  
  1428.     ; eax = u  --------wwwwwwwwffffffffffffffff  (w=whole, f=fractional)
  1429.     ; ebx = v  --------wwwwwwwwffffffffffffffff
  1430.     ; ecx = scratch register
  1431.     mov   ecx, eax
  1432.     shl   eax, 2
  1433.     and   ecx, 00000000000001111111111111111111b
  1434.     and   eax, 11111111111000000000000000000000b
  1435.     or    eax, ecx            
  1436.     mov   ecx, ebx
  1437.     shl   ebx, 5
  1438.     and   ecx, 00000000000000111111111111111111b
  1439.     and   ebx, 11111111100000000000000000000000b
  1440.     or    ebx, ecx            
  1441.     ; eax = u  ------wwwww--wwwffffffffffffffff
  1442.     ; ebx = v  ---wwwwww-----wwffffffffffffffff
  1443.  
  1444.  
  1445. Adding dudx and dvdx to u and v in this format can be done with the following
  1446. code (all variables are in the converterd format):
  1447.  
  1448.     uc = (uc | 0x00180000) + dudx; 
  1449.     vc = (vc | 0x007c0000) + dvdx;
  1450.  
  1451.  
  1452.     ; eax = u  ------wwwww--wwwffffffffffffffff
  1453.     ; ebx = v  ---wwwwww-----wwffffffffffffffff
  1454.     ; dudx, dvdx = 16:16 bit converted to this format 
  1455.     or    eax, 00000000000110000000000000000000b    ; fill the bit-gap in u
  1456.     or    ebx, 00000000011111000000000000000000b    ; fill the bit-gap in v
  1457.     add   eax, [dudx]
  1458.     add   ebx, [dvdx]
  1459.  
  1460.  
  1461. In a mail sent to me, Russel Simmons preresented the following method to
  1462. reorder the bits to acheive a simpler inner loop by eliminating a bit-gap:
  1463.  
  1464.  
  1465.     In one post, someone suggested a bit structure to find the corect
  1466.     position in your tiled texture given u and v. He suggested something
  1467.     like:
  1468.     
  1469.     high bits of v | high bits of u | low bits of v | low bits of u
  1470.     
  1471.     This way the high bits of u and v determine which tile our texel is in,
  1472.     and the low bits of u and v determine where in our tile the texel is.
  1473.     If we store our tiles in a different manner, we can simplify this to:
  1474.  
  1475.     high bits of u | high bits of v | low bits of v | low bits of u
  1476.  
  1477.     which is in other words:
  1478.  
  1479.     high bits of u | all bits of v | low bits of u
  1480.  
  1481.     In order to facilitate this, instead of storing our tiles in this order:
  1482.  
  1483.     -------------
  1484.     | 0| 1| 2| 3| ...  (here i am showing the upper 4x4 tiles of a 256x256
  1485.     -------------       texture store in 8x8 tiles)
  1486.     |32|33|34|35| ...
  1487.     -------------       Original Method
  1488.     |64|65|66|67| ...
  1489.     -------------
  1490.     |96|97|98|99| ...
  1491.     -------------
  1492.     |  |  |  |  |
  1493.  
  1494.     store them in this order:
  1495.  
  1496.     -------------
  1497.     | 0|32|64|96| ...  (here i am showing the upper 4x4 tiles of a 256x256
  1498.     -------------       texture store in 8x8 tiles)
  1499.     | 1|33|65|97| ...
  1500.     -------------       New Method, in order to acheive a simpler inner loop
  1501.     | 2|34|66|98| ...
  1502.     -------------
  1503.     | 3|35|67|99| ...
  1504.     -------------
  1505.     |  |  |  |  |
  1506.  
  1507.     Also, if we are storing our bitmap in a tiled fashion, then it would
  1508.     greatly improve our cache performance if we can back and forth across
  1509.     scan lines.. in other words alternate the direction we scan across lines.
  1510.     Say we have just scanned forward across one scan line. If we start
  1511.     backwards across the next scan line, we are likely to be pulling texels
  1512.     from the same tiles as we were at the end of the previous scan line.
  1513.  
  1514.  
  1515. The last part about alternating the drawing direction is definitely something
  1516. to try out!
  1517.  
  1518. I was hoping I would be able to present some code here that uses all these
  1519. techniques and 16:16 bit interpolation in a slick inner loop but due to lack
  1520. of time and the fact that I'm fed up with this document, I leave this to you.
  1521.  
  1522.  
  1523.  
  1524. 21. The code cache
  1525. ------------------
  1526.  
  1527. The cool thing about Pentiums is that it can execute two instructions in
  1528. parallel. This is called instruction pairing. But there is a lot of rules
  1529. that must be fulfilled for the pairing to take place. One rule is that both
  1530. instructions must already be in the code cache. This means that the first
  1531. time trough a inner loop, no instructions will pair. There is one exception
  1532. to this rule. If the first instruction is a 1 byte instruction, e.g. inc eax,
  1533. and the other is a simple instruction, then they will pair the first time.
  1534.  
  1535. If by chance our inner loop happens to be in the code cache, by modifying an
  1536. instruction in the inner loop (selfmodifying code) the cacheline where we
  1537. did the modification will be marked as not up to date. So that cacheline
  1538. must be loaded into the cache again before we can execute the inner loop
  1539. again. Loading of code cachelines seems to be exceptionally slow also. In
  1540. other words, we have found yet another source of delay.
  1541.  
  1542. So to have a completely unrolled loop that almost fills up the whole code
  1543. cache and also is selfmodifying is a pretty bad idea on the Pentium. On the
  1544. other hand, we are not modifying the loop for each scanline so chances are
  1545. that parts of it will be in the code cache from drawing the previous
  1546. scanline.
  1547.  
  1548.  
  1549.  
  1550. 22. Some pairing rules
  1551. ----------------------
  1552.  
  1553. As mentioned above, the Pentium can execute two instructions in parallel.
  1554. This is possible because the CPU has dual integer pipelines, they are
  1555. called the U and V pipelines. The Pentium has a so called superscalar
  1556. architecture. The U pipeline is fully equipped and can execute all integer
  1557. instructions. The V pipeline on the other hand is a bit crippled and can only
  1558. execute simple, RISC type instructions.
  1559.  
  1560. Simple instructions are:
  1561.  
  1562.  mov, inc, dec, add, adc, sub, sbb,
  1563.  and, or, xor, cmp, test, push, pop,
  1564.  lea, jmp, call, jcc, nop, sar, sal,
  1565.  shl, shr, rol, ror, (rcl), (rcr)
  1566.  
  1567. (What I've heard there are different opinions on if the shift/rotate
  1568. instructions are pairable or not. The book I have here states that these
  1569. instructions are pairable but can only execute in the U pipeline)
  1570.  
  1571.  
  1572. The first pairing rule is that both instructions must be simple instructions.
  1573. Also, no segment registers can be involved in the instructions.
  1574.  
  1575. Another rule is that the two instructions must be completely independent of
  1576. each other. Also they must not write to the same destination register/memory.
  1577. They can read from the same register though. Here are some examples:
  1578.  
  1579.     add   ecx, eax      ; store result in ecx
  1580.     add   edx, ecx      ; get result from ecx. No pairing!
  1581.  
  1582.     mov   ecx, eax
  1583.     mov   edx, ecx      ; No pairing!
  1584.  
  1585.     mov   al, bh        ; al and ah is in the same register
  1586.     mov   ah, ch        ; No pairing!
  1587.  
  1588.  
  1589.     mov   ecx, eax      ; read from the same register 
  1590.     mov   edx, eax      ; Pairs ok.
  1591.  
  1592.     mov   ecx, eax      ; note eax in this example
  1593.     add   eax, edx      ; Pairs ok.
  1594.  
  1595. There are two exception to this rule. Namely the flag register and the stack
  1596. pointer. Intel has been kind enough to optimize these.
  1597.  
  1598.     dec   ecx           ; modifies the flag register
  1599.     jnz   @@inner       ; Pairs ok.
  1600.  
  1601.     push  eax           ; both instructions are accessing esp
  1602.     push  ebx           ; Pairs ok.
  1603.  
  1604.  
  1605. So for example the loop we used to calculate the lookup table with, all
  1606. instructions are simple and not dependent on the previous one. The 8
  1607. instructions should execute in 4 clock ticks.
  1608.  
  1609.  @@mklookup:
  1610.     mov   eax, ecx          
  1611.     add   ecx, edi      ; Pairs ok.
  1612.     mov   al, bh
  1613.     add   ebx, esi      ; Pairs ok.
  1614.     mov   [edx], eax
  1615.     add   edx, 4        ; Pairs ok.
  1616.     dec   ebp
  1617.     jnz   @@mklookup    ; Pairs ok.
  1618.  
  1619.  
  1620.  
  1621. 23. Pipeline delays
  1622. -------------------
  1623.  
  1624. There are a whole bunch of these that will delay the pipelines:
  1625.  
  1626.  - data cache memory bank conflict
  1627.  - address generation interlock, AGI
  1628.  - prefix byte delay
  1629.  - sequencing delay
  1630.  
  1631. I personally think that the AGI is most important to consider in the case
  1632. of tight inner loops. Because that is what's happening in a inner loop, where
  1633. we are calculating an address and need it right away to access some data.
  1634. There will be a AGI delay if a register used in a effective address
  1635. calculation is modified in the previous clock cycle. So if we have our
  1636. instructions nicely pairing we might have to put 3 instructions in between to
  1637. avoid the AGI delay.
  1638.  
  1639.     add   esi, ebx      ; Move the array pointer.
  1640.     mov   eax, [esi+8]  ; AGI delay. You just modified esi.
  1641.  
  1642.  
  1643.     add   esi, ebx      ; Move the array pointer.
  1644.     add   ebx, ecx      ; Do something useful here
  1645.     inc   edi           ;  "
  1646.     add   ebp, 4        ;  "
  1647.     mov   eax, [esi+8]  ; Now it's OK to access the data. No AGI delay.
  1648.  
  1649.  
  1650. If you don't have any useful instructions to fill out the gap with you could
  1651. try to swap the two instructions so that you access the data first and then
  1652. modify the index register. 
  1653.  
  1654.     mov   eax, [esi+8]
  1655.     add   esi, ebx      ; Pairs ok. No AGI delay.
  1656.  
  1657.  
  1658.  
  1659. There are a lot more rules one must follow so I suggest you buy a good book
  1660. on the subject. I don't know of any free info about this on the net as of
  1661. this writing. Maybe you'll find something at Intel's www-site
  1662. (http://www.intel.com). Anyway, a book that got me started was: "Pentium
  1663. Processor Optimization Tools" by Michael L. Schmit  ISBN 0-12-627230-1
  1664. This book has a few minor errors and some of the explanations are a bit
  1665. cryptic but it is a good starting point. The way to really learn is to get
  1666. the basics from e.g. a book and then time actual code to see what is faster
  1667. and what's not.
  1668.  
  1669.  
  1670.  
  1671. 24. The time stamp counter
  1672. --------------------------
  1673.  
  1674. The Pentium has a built in 64 bit counter called the Time Stamp Counter that
  1675. is incremented by 1 for each clock tick. To read the counter you use the
  1676. semi-undocumented instruction RDTSC (db 0fh,31h). This will load the low 32
  1677. bit of the counter into EAX and the high 32 bit into EDX. Perfect for timing
  1678. code! 
  1679.  
  1680.     ; First time the overhead of doing the RDTSC instruction
  1681.     db      0fh,31h         ; hex opcode for RDTSC
  1682.     mov     ebx, eax        ; save low 32 bit in ebx
  1683.     db      0fh,31h         
  1684.     sub     eax, ebx        ; overhead = end - start
  1685.     mov     [oh_low], eax
  1686.  
  1687.     ; Now do the actual timing
  1688.     db      0fh,31h         
  1689.     mov     [co_low], eax
  1690.     mov     [co_hi], edx
  1691.  
  1692.     ; Run some inner loop here of whatever you want to time
  1693.  
  1694.     db      0fh,31h         
  1695.     sub     eax, [co_low]   ; ticks = end - start
  1696.     sbb     edx, [co_hi]
  1697.     sub     eax, [oh_low]   ; subtract overhead
  1698.     sbb     edx, 0
  1699.     ; Number of clock ticks is now in  edx:eax
  1700.  
  1701.  
  1702. You'll notice that I first time the overhead of doing the RDTSC instruction.
  1703. This might be a bit overkill but it's no harm in doing it. Note also that I
  1704. ignore the high 32 bit. The overhead should not be more than 2^32 clock
  1705. ticks anyway. The RDTSC can be a privileged instruction under some extenders
  1706. (?) but still be available (under the control of the extender) so there might
  1707. actually be a overhead to time.
  1708.  
  1709. You can usually ignore the high 32 bit. Using only the low 32 bit will allow
  1710. a maximum of 2^32 clock ticks which is 35 seconds on a Pentium 120 MHz.
  1711.  
  1712. When you are timing your code e.g. when you have done some optimizations on
  1713. your texture mapper, don't time just one triangle over and over. Time how
  1714. long it takes to draw a complete object with hundreds (thousands) of
  1715. triangles. Then you'll know if that optimization made any difference.
  1716.  
  1717.  
  1718.  
  1719. 25. Branch prediction
  1720. ---------------------
  1721.  
  1722. The Pentium has some sort of lookup table called the Branch Target Buffer
  1723. (BTB) in which it stores the last 256 branches. With this it tries to
  1724. determine the destination for each jump or call. This is done by keeping a
  1725. history of whether a jump was taken or not the last time it was executed. If
  1726. the prediction is correct then a conditional jump takes only 1 clock tick to
  1727. execute.
  1728.  
  1729. Because the history mechanism only remembers the last time the jump was
  1730. executed, the prediction will always fail if we jump different each time.
  1731. There is a 4-5 clock tick delay if the prediction fails.
  1732.  
  1733. The branch prediction takes place in the second stage of the instruction
  1734. pipeline and predicts if whether a branch will be taken or not and its
  1735. destination. Then it starts filling the other instruction prefetch queue
  1736. with instructions from the branch destination. If the prediction was wrong,
  1737. then both prefetch queue must be flushed and prefetching restarted.
  1738.  
  1739. So to avoid this delay you should strive to use simple loops that always
  1740. takes the jump or always not takes the jump. Not like the following that
  1741. jumps different depending on the carry flag.
  1742.  
  1743.  
  1744.     jmp   @@inner
  1745.   @@extra:
  1746.     ....                ; Do something extra when we get carry overflow
  1747.     dec   ebp
  1748.     jz    @@done
  1749.   @@inner:
  1750.     ....                ; Do something useful here
  1751.     add   eax, ebx
  1752.     jc    @@extra       ; Jump on carry overflow
  1753.     dec   ebp
  1754.     jnz   @@inner
  1755.   @@done:
  1756.  
  1757. In this loop it's the 'jc @@extra' instruction that will mess up the branch
  1758. prediction. Sometimes the jump will be taken and sometimes not. The typical
  1759. way of doing masking with compares and jumps has this problem also.
  1760.  
  1761.  
  1762.  
  1763. 26. Reference
  1764. -------------
  1765.  
  1766. Most of the Pentium specific information on optimization was found in the
  1767. book: "Pentium Processor Optimization Tools" by Michael L. Schmit
  1768. ISBN 0-12-627230-1
  1769.  
  1770.  
  1771.  
  1772. 27. Where to go from here
  1773. -------------------------
  1774.  
  1775. When you have implemented your texture mapper you automatically also have
  1776. Phong shading and environment mapping. It's only a matter of making a
  1777. suitable bitmap and to use the normal vectors at each triangle vertex to get
  1778. the u and v values.
  1779.  
  1780. From there the step is not far from combining Phong shading and texture
  1781. mapping. And then adding bumps to all this. The only difficult part is that
  1782. you need to interpolate 4 variables in the inner loop when you do
  1783. Phong-texture, environment-bump or Phong-texture-bump and still have
  1784. registers left for pointers and loop counter. These shadings can't really be
  1785. called "fast" as the inner loops will become pretty ugly. They can definitely
  1786. be called real time though.
  1787.  
  1788.  
  1789.  
  1790. 28. Credits and greetings
  1791. -------------------------
  1792.  
  1793. Juan Carlos Arevalo Baeza (JCAB/Iguana-VangeliSTeam) <jarevalo@daimi.aau.dk>
  1794. Wilco Dijkstra                      <wdijkstr@hzsbg01.att.com>
  1795. Kevin Baca                          <kbaca@skygames.com>
  1796. Sean L. Palmer                      <sean@delta.com>
  1797. Tiziano Sardone                     <tiz@mail.skylink.it>
  1798. Mark Pursey                         <nerner@world.net>
  1799. Dare Manojlovic                     <tangor@celje.eunet.si>
  1800. Russel Simmons   (Armitage/Beyond)  <resimmon@uiuc.edu>
  1801. Aatu Koskensilta (Zaphod.B)         <zaphod@sci.fi>   
  1802. Otto Chrons      (OCoke)    (a legend)
  1803. Nix/Logic Design            (a cool coder)
  1804. Phil Carmody     (FatPhil)  (The optimizing guru, why all this silence?)
  1805. Jmagic/Complex              (another legend)
  1806. MacFeenix                   (you are young)
  1807. BX                          (keep on coding)
  1808. thefear                     (a cool swede)
  1809. John Gronvall               (MIPS R8000 rules!)
  1810. LoZEr                       (when will PacMan for Linux be out?)
  1811. Addict, Damac, Dice, Doom, Swallow, Wode / Doomsday  (a bunch of finns ;)
  1812.  
  1813.  
  1814. When I started out writing this document I didn't know half of what I now
  1815. know about texture mapping. I've learned a lot and this is much because of
  1816. those 12 first persons in the credits and greetings list. Thanks a lot for
  1817. the help. I hope that the readers of this document also will learn something.
  1818.  
  1819. If you truly find this document useful, you could consider giving me a small
  1820. greeting in your production. That would be cool.
  1821.  
  1822. <EOF>
  1823.